/*
 * Copyright (c) 2010 CCX(China) Co.,Ltd. All Rights Reserved.
 *
 * This software is the confidential and proprietary information of
 * CCX(China) Co.,Ltd. ("Confidential Information").
 * It may not be copied or reproduced in any manner without the express 
 * written permission of CCX(China) Co.,Ltd.
 * 
 *	Created on 2010-12-13 下午05:16:14
 */
package cn.com.ccxe.core.db;

import java.io.File;
import java.io.IOException;
import java.util.Comparator;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.com.ccxe.core.crawl.listing.DataUpdater;
import cn.com.ccxe.core.db.util.ListPageLinkCompartor;
import cn.com.ccxe.core.db.util.ListPageLinkTupleBinding;
import cn.com.ccxe.core.entity.ListPageLink;
import cn.com.ccxe.core.util.CodeUtil;
import cn.com.ccxe.core.util.Configurations;

import com.sleepycat.bind.tuple.TupleBinding;
import com.sleepycat.je.Cursor;
import com.sleepycat.je.CursorConfig;
import com.sleepycat.je.DatabaseConfig;
import com.sleepycat.je.DatabaseEntry;
import com.sleepycat.je.DatabaseException;
import com.sleepycat.je.Environment;
import com.sleepycat.je.EnvironmentConfig;
import com.sleepycat.je.OperationStatus;


/**
 * 列表页面库。<br>
 *
 * @author hetao
 */
public class ListPageDB extends BasicDB<ListPageLink>{

	
	private static final String 	DATABASE_NAME = "LIST_PAGE_DB";
	final static Logger 			logger = LoggerFactory.getLogger(ListPageDB.class);
	//列表页的更新时间，默认为5分钟。
	private static int 				LIST_PAGE_FETCH_TIME = (Configurations.getInt("listPage.fetch.time", 5));
	private static Environment 		environment;
	private static final String 	DATABASE_PATH = "E:/myworkspace/monitor/db/LIST_PAGE_DB";
	private static ListPageDB 		LIST_PAGE_DB;
	private volatile int 			updateCount = 0;	//更新记录计数器.
	
	ListPageDB() throws Exception {
		environment = setup(DATABASE_PATH);
		DatabaseConfig dbConfig = new DatabaseConfig();
		dbConfig.setAllowCreate(true);
		dbConfig.setTransactional(false);
		dbConfig.setDeferredWrite(true);
		dbConfig.setDuplicateComparator(getComparator());// 设置判断重复的比较器
		dbConfig.setSortedDuplicates(false);// 是否允许重复的记录
		database = environment.openDatabase(null, DATABASE_PATH, dbConfig);
		if(database != null) {
			logger.info("数据库【{}】创建成功",DATABASE_NAME);
		}
	}
	
	@Override
	public void put(String key, ListPageLink e) {
		ListPageLink tmp = getFirst(key);
		if(tmp != null) {
			return ;
		}
		super.put(key, e);
	}

	public String getDatabaseName() {
		return DATABASE_NAME;
	}
	
	@Override
	public void sync() {
		logger.info("数据库【{}】现完成数据同步！",getDatabaseName());
		super.sync();
	}
	
	@Override
	public void close() {
		super.close();
		environment.cleanLog();
		environment.close();
	}

	@Override
	protected Class<? extends Comparator<byte[]>> getComparator() {
		return ListPageLinkCompartor.class;
	}
	
	public synchronized static ListPageDB getInstance() {
		try {
			if (LIST_PAGE_DB == null) {
				logger.info("数据库【{}】未被创建，将重新创建！", DATABASE_NAME);
				LIST_PAGE_DB = new ListPageDB();
				return LIST_PAGE_DB;
			}
		} catch (Exception e) {
			logger.error("数据库安装失败！");
			System.exit(-1);
		}
		return LIST_PAGE_DB;
	}
	
	/**
	 * 遍历{@link ListPageDB}，将符合抓取规则的链接添加至{@link ListPageWorkQueues}
	 * @param workQueues
	 * @param dataUpdater
	 */
	public void copy(ListPageWorkQueues workQueues, DataUpdater dataUpdater ) {
		updateCount = 0 ;
		Cursor cursor = getCursor(null,CursorConfig.READ_UNCOMMITTED);
		long listDBSize = this.size();
		OperationStatus result = null;
		DatabaseEntry keyEntry = new DatabaseEntry();
		DatabaseEntry valueEntry = new DatabaseEntry();
		int matches = 0;

		try {
			lock.lock();
			result = cursor.getFirst(keyEntry, valueEntry, null);
			while (matches < listDBSize && isSuccess(valueEntry, result)) {
				matches++;
				ListPageLink e = convert(valueEntry);
				//验证更新
				boolean flag = dataUpdater.checkUpdate(e);
				if(flag) {
					workQueues.put(e.getPath(), e);
					updateCount++;
				}
				result = cursor.getNext(keyEntry, valueEntry, null);
			}
		} finally {
			closeCursor(cursor);
			lock.unlock();
		}
		if(logger.isInfoEnabled()) {
			Object [] parms = new Object[]{
						DATABASE_NAME,
						listDBSize,
						updateCount,
						workQueues.getDatabaseName()
						};
			logger.info("{}条数据共有 {} 条数据，其中有 {} 数据添加至 {}。", parms);
		}
	}

	@Override
	protected TupleBinding<ListPageLink> getTupleBinding() {
		return new ListPageLinkTupleBinding();
	}
	
	@Override
	public void update(String key, ListPageLink e) {
		DatabaseEntry valueEntry;
		DatabaseEntry keyEntry;
		try {
			lock.lock();
			valueEntry = new DatabaseEntry();
			getTupleBinding().objectToEntry(e, valueEntry);
			keyEntry = new DatabaseEntry(key.getBytes());
			database.put(null, keyEntry, valueEntry);
		} catch (DatabaseException ex) {
			throw ex;
		} finally {
			lock.unlock();
		}
		
	}

	@SuppressWarnings("unused")
	private boolean isFound(ListPageWorkQueues workQueues, ListPageLink key) {
		return workQueues.getFirst(key.getPath()) == null;
	}

	/**
	 *  
	 * @return true 为需要更新
	 */
	@SuppressWarnings("unused")
	private boolean checkUpdate(ListPageLink e) {
		int i = (CodeUtil.getDate() - (e.getFetchTime() + LIST_PAGE_FETCH_TIME));
//		logger.info("还有{} 分钟，将会更新。",i);
		return i >= 0;
	}
	
	/**
	 * 配置环境
	 * 
	 * @return
	 */
	private EnvironmentConfig deploy() {
		EnvironmentConfig envConfig = new EnvironmentConfig();
		envConfig.setAllowCreate(true);
		envConfig.setTransactional(true);
		envConfig.setLocking(true);
		return envConfig;
	}

	public Environment setup(String path) throws Exception {
		if (path == null || path.length() == 0) {
			throw new IOException("请指定数据库目录！");
		}
		File folder = new File(path); // 数据库安装目录
		File envHome = new File(path + "/frontier");// 数据库环境的主目录
		createHome(folder, envHome);
		EnvironmentConfig envConfig = deploy(); // 环境属性设置
		return new Environment(envHome, envConfig);
	}
	
	private void createHome(File folder, File envHome) throws IOException {
		if (!folder.exists()) {
			if (!folder.mkdirs()) {
				logger.info("创建安装目录失败");
				throw new IOException();
			}
			if (!envHome.exists()) {
				if (!envHome.mkdir()) {
					logger.info("数据库安装目录创建失败");
					throw new IOException();
				}
			}
		}
	}
	public static void main(String[] args) {
		int fetchTime = CodeUtil.getDate()-10;
		System.out.println( (CodeUtil.getDate() - (fetchTime + LIST_PAGE_FETCH_TIME)));
	}
	
}
